#include<iostream>
#include<pthread.h>
#include<queue>
#include<unistd.h>
using namespace std;


class BlockQueue
{
  private:
    queue<int> q;
    size_t cap;
    pthread_mutex_t mutex;
    pthread_cond_t c_cond;//消费者在此条件变量下等
    pthread_cond_t p_cond;//生产者在此条件变量下等
    pthread_mutex_t c_mutex;//消费者竞争的锁
    pthread_mutex_t p_mutex;//生产者竞争的锁
  public:
    BlockQueue(size_t _cap)
      :cap(_cap)
    {
        //初始化锁和条件变量
        pthread_mutex_init(&mutex,nullptr);
        pthread_cond_init(&c_cond,nullptr);
        pthread_cond_init(&p_cond,nullptr);
        pthread_mutex_init(&c_mutex,nullptr);
        pthread_mutex_init(&p_mutex,nullptr);
    }
    void LockQueue()
    {
      pthread_mutex_lock(&mutex);
    }
    void ULockQueue()
    {
      pthread_mutex_unlock(&mutex);
    }
    void UCLockQueue()
    {
      pthread_mutex_unlock(&c_mutex);
    }
    void UPLockQueue()
    {
      pthread_mutex_unlock(&p_mutex);
    }
    void CLockQueue()
    {
      pthread_mutex_lock(&c_mutex);
    }
    void PLockQueue()
    {
      pthread_mutex_lock(&p_mutex);
    }
    bool IsFull()
    {
      return cap == q.size(); 
    }
    bool IsEmpty()
    {
      return q.empty();
    }

    void  WakeUpCostumer()
    {
      //通知消费者
      pthread_cond_signal(&c_cond);
     // cout<<"wake up Costumer..."<<endl;
    }
    void  ProductWait()
    {
      // 生产者等待
      pthread_cond_wait(&p_cond,&mutex);
     // cout<<"Product wait..."<<endl;
    }
    void WakeUpProduct()
    {
      //通知生产者
      pthread_cond_signal(&p_cond);
     // cout<<"wake up Product..."<<endl;
    }
    void CostumerWait()
    {     
      // 消费者等待
      pthread_cond_wait(&c_cond,&mutex);
     // cout<<"Costumer wait..."<<endl;
    }
    void push(int &in)
    {
      //先申请锁,判断队列是否满
      //满了要通知消费者，生产者等待
      LockQueue();
      while(IsFull())
      {
       // WakeUpCostumer();
        cout<<"通知消费者消费数据"<<endl;
        ProductWait();
      }
      q.push(in);
      if(q.size() >= cap/2)
      {
        WakeUpCostumer();
      }
      ULockQueue();
    }
    void pop(int& out)
    {
      //消费者取数据,先申请锁
      //判断队列是否有数据,没有则通知生产者,自己等待
      LockQueue();
      while(IsEmpty())
      {
         //WakeUpProduct();
         cout<<"通知生产者生产数据"<<endl;
         CostumerWait();
      }
      out = q.front();
      q.pop();
      if(q.size() <= cap/2)
      {

         WakeUpProduct();
      }
      ULockQueue();

    }
    ~BlockQueue()
    {
      //释放锁和条件变量
      pthread_mutex_destroy(&mutex);
      pthread_cond_destroy(&c_cond);
      pthread_cond_destroy(&p_cond);
      pthread_mutex_destroy(&c_mutex);
      pthread_mutex_destroy(&p_mutex);
    }
};
